package com.gitee.huanminabc.utils_tools.class_extend.javassist;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import lombok.SneakyThrows;
import java.util.*;

/**
 * @author huanmin
 * @date 2024/2/26
 */
public class AopLoader extends ClassLoader {
    private ClassPool source;
    //key就是需要代理的目录类,而一个类可以被多个代理, 但是多个代理的类名不能重复
    private static Map<String, Map<String,AopInfoBo>>  aspectMap;
    static {
       aspectMap = new HashMap<>();
    }

    public void addAspect(AopInfoBo aspect){
        String name = aspect.getClassPath();
        if (aspectMap.containsKey(name)){
            Map<String,AopInfoBo> stringClassMap = aspectMap.get(name);
            if (stringClassMap.containsKey(aspect.getClassPath())){
                throw new RuntimeException(aspect.getClassPath()+"->增强类已经存在");
            }else {
                stringClassMap.put(aspect.getClassPath(),aspect);
            }
        }else {
            Map<String,AopInfoBo> objectObjectHashMap = new HashMap<>();
            objectObjectHashMap.put(aspect.getClassPath(),aspect);
            aspectMap.put(name,objectObjectHashMap);
        }

    }
    public void addAspects(List<AopInfoBo> aspect){
        for (AopInfoBo aClass : aspect) {
            addAspect(aClass);
        }
    }
    public final void addAspects(AopInfoBo ...aspect){
        addAspects(Arrays.asList(aspect));
    }

    public AopLoader(ClassPool source) {
        this.source = source;
    }

    @SneakyThrows
    @Override
    public Class findClass(String name) {
            //搜索当前的ClassLoader是否加载过此类
            Class<?> loadedClass = findLoadedClass(name);
            if (loadedClass != null) {
                return loadedClass;
            }
            //如果没有加载过那么就获取类,然后进行代理
            CtClass cc = source.get(name);
            if (cc==null){
                throw new ClassNotFoundException( "没有找到"+name+"的类");
            }
            Map<String, AopInfoBo> stringClassMap = aspectMap.get(cc.getName());
            if (stringClassMap==null){//表示此类没有代理切片
                throw new ClassNotFoundException( "没有找到"+name+"的增强对象");
            }

            ArrayList<AopInfoBo> classes = new ArrayList<>(stringClassMap.values());
            for (AopInfoBo  aClass : classes) {
                CtClass ctClass = source.get(aClass.getClassPath());
                CtClass[] methodTypes = ClassExtend.getMethodTypes(aClass.getArgs());
                CtMethod declaredMethod = ctClass.getDeclaredMethod(aClass.getMethodName(), methodTypes);
                ClassExtend.aopExtends(source, cc, declaredMethod, classes);
            }
            //删除已经处理的类
            aspectMap.remove(cc.getName());
            //将修改后的类加载到ClassLoader中
            byte[] b = cc.toBytecode();
            Class<?> aClass = defineClass(name, b, 0, b.length);
            return aClass;

    }

}
